package coordinator

import (
	"adai.design/homemaster/log"
	"encoding/binary"
)

const (
	SerialLinkStartChar = 0x01
	SerialLinkEscChar   = 0x02
	SerialLinkEndChar   = 0x03
)

const (
	SerialLinkMsgTypeGetVersion      = 0x0010
	SerialLinkMsgTypeVersionList     = 0x8010
	SerialLinkMsgTypeStartNetwork    = 0x0024
	SerialLinkMsgTypeNetworkStateReq = 0x0009
	SerialLinkMsgTypeNetworkStateRsp = 0x8009

	SerialLinkMsgTypeManagementLqiRequest  = 0x004E
	SerialLinkMsgTypeManagementLqiResponse = 0x804E

	SerialLinkMsgTypeOnOffNoEffects = 0x0092

	SerialLinkMsgMacAddressRequest  = 0x0041
	SerialLinkMsgMacAddressResponse = 0x8041

	SerialLinkMsgManagementLeaveRequest = 0x0047
	SerialLinkMsgLeaveIndication        = 0x8048

	SerialLinkMsgTypeSimpleDescriptorRequest  = 0x0043
	SerialLinkMsgTypeSimpleDescriptorResponse = 0x8043

	SerialLinkActiveEndpointRequest  = 0x0045
	SerialLinkActiveEndPointResponse = 0x8045

	SerialLinkPermitJoinRequest = 0x0049
	SerialLinkDeviceAnnounce    = 0x004D

	SerialLinkMsgTypeReadAttributeRequest  = 0x0100
	SerialLinkMsgTypeReadAttributeResponse = 0x8100

	SerialLinkMsgTypeDefaultResponse   = 0x8101
	SerialLinkMsgTypeAttributeResponse = 0x8102

	SerialLinkMsgTypeMoveToLevel             = 0x0081
	SerialLinkMsgTypeMoveToColour            = 0x00B7
	SerialLinkMsgTypeMoveToColourTemperature = 0x00C0
)

type Message struct {
	MsgT uint16
	Data []byte
}

func (msg *Message) Encode() ([]byte, error) {
	data := make([]byte, 7+len(msg.Data))
	// 组织数据
	data[0] = SerialLinkStartChar
	binary.BigEndian.PutUint16(data[1:], uint16(msg.MsgT))
	binary.BigEndian.PutUint16(data[3:], uint16(len(msg.Data)))

	var check uint8 = 0x00
	check = check ^ data[1]
	check = check ^ data[2]
	check = check ^ data[3]
	check = check ^ data[4]
	for _, v := range msg.Data {
		check = check ^ v
	}
	data[5] = check
	copy(data[6:], msg.Data)
	data[len(data)-1] = SerialLinkEndChar

	// 编码数据
	n := len(data)
	for _, v := range data[1 : len(data)-1] {
		if v < 0x10 {
			n = n + 1
		}
	}
	sdata := make([]byte, n)
	sdata[0] = data[0]
	sdata[len(sdata)-1] = data[len(data)-1]
	j := 1
	for i := 1; i < len(data)-1; i++ {
		if data[i] >= 0x10 {
			sdata[j] = data[i]
			j++
		} else {
			sdata[j] = SerialLinkEscChar
			j++
			sdata[j] = data[i] ^ 0x10
			j++
		}
	}
	return sdata, nil
}

func newMessage(buf []byte) *Message {
	log.Printf("message write -> %x\n", buf)
	data := make([]byte, len(buf))
	j := 0
	for i := 0; i < len(buf); i++ {
		if buf[i] == 0x02 {
			i++
			data[j] = buf[i] & 0x0F
			j++
		} else {
			data[j] = buf[i]
			j++
		}
	}

	//log.Printf("message output: %x\n", data[:j])
	if j < 8 || data[0] != 0x01 || data[j-1] != 0x03 {
		//log.Printf("message invalid: %x\n", data[:j])
		return nil
	}

	msg := &Message{
		MsgT: binary.BigEndian.Uint16(data[1:]),
		Data: data[6 : j-1],
	}
	log.Printf("message code: %x\n", data[:j])
	if msg.MsgT != 0x8000 {
		log.Printf("msg: %04x data: %x\n", msg.MsgT, msg.Data)
	}

	return msg
}

func GetVersion() error {
	msg := &Message{MsgT: SerialLinkMsgTypeGetVersion, Data: nil}
	sdata, err := msg.Encode()
	if err != nil {
		return err
	}
	log.Printf("send: %x\n", sdata)
	return nil
}

//d86b47010006f00023000403030303

func StartNetwork() error {
	msg := &Message{MsgT: SerialLinkMsgTypeStartNetwork, Data: nil}
	sdata, err := msg.Encode()
	if err != nil {
		return err
	}
	log.Printf("send: %x\n", sdata)
	return nil
}

func NetworkState() error {
	msg := &Message{MsgT: SerialLinkMsgTypeNetworkStateReq, Data: nil}
	sdata, err := msg.Encode()
	if err != nil {
		return err
	}
	log.Printf("send: %x\n", sdata)
	return nil
}

func ManagementLqiRequest() error {
	msg := &Message{MsgT: SerialLinkMsgTypeManagementLqiRequest, Data: []byte{0x00, 0x00, 0x00}}
	sdata, err := msg.Encode()
	if err != nil {
		return err
	}
	log.Printf("send: %x\n", sdata)
	return nil
}
